/*
 * TFileUtil.h
 *
 *  Created on: 2014年3月3日
 *      Author: zhengchuanjiang
 */

#ifndef TFILEUTIL_H_
#define TFILEUTIL_H_


#include <string>
#include <stdio.h>
#include <fstream>
#include <vector>
#include <functional>
#include <utility>
#include <algorithm>

#undef MIN

namespace comn
{

class FileUtil
{
public:
	static const size_t BUFFER_SIZE = 1024 * 128;

    static bool load(std::string& str, const char* filepath)
    {
        FILE* pFile = NULL;
        #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
        pFile = _fsopen(filepath, "rb", _SH_DENYNO);
        #else
        pFile = fopen(filepath, "rb");
        #endif //

        if (!pFile)
        {
            return false;
        }

        str.reserve(1024 * 1024 * 1);

        char* buffer = new char[BUFFER_SIZE];
        while (!feof(pFile))
        {
            size_t count = fread(buffer, 1, BUFFER_SIZE, pFile);
            if (count == 0)
            {
                break;
            }

            str.append(buffer, count);
        }

		delete[] buffer;

        fclose(pFile);
        return true;
    }

    static bool write(const char* data, size_t length, const char* filepath, bool append)
    {
        return write((const unsigned char*)data, length, filepath, append);
    }

    static bool write(const unsigned char* data, size_t length, const char* filepath, bool append)
    {
        FILE* pFile = NULL;
        if (append)
        {
            #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
            pFile = _fsopen(filepath, "ab", _SH_DENYWR);
            #else
            pFile = fopen(filepath, "ab");
            #endif //
        }
        else
        {
            #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
            pFile = _fsopen(filepath, "wb", _SH_DENYWR);
            #else
            pFile = fopen(filepath, "wb");
            #endif //
        }

        if (!pFile)
        {
            return false;
        }

        fwrite(data, 1, length, pFile);


        fclose(pFile);
        return true;
    }

    static bool dump(const std::string& data, const char* filepath)
    {
        return write(data.c_str(), data.length(), filepath, false);
    }

    static bool append(const std::string& data, const char* filepath)
    {
        return write(data.c_str(), data.length(), filepath, true);
    }

    static bool load(const char* filepath, std::vector< std::string>& lines)
    {
        std::ifstream ifs(filepath);
        if (!ifs.is_open())
        {
            return false;
        }

        std::string line;
        while (!ifs.eof())
        {
			std::getline(ifs, line);
            lines.push_back(line);
        }

        ifs.close();
        return true;
    }

	typedef std::function< bool(const std::string& line) >	LinePredicate;
	static bool scanLine(const char* filepath, LinePredicate pred)
	{
		std::ifstream ifs(filepath);
		if (!ifs.is_open())
		{
			return false;
		}

		std::string line;
		while (!std::getline(ifs, line).eof())
		{
			if (!pred(line))
			{
				break;
			}
		}

		ifs.close();
		return true;
	}

	template < class Pred >
	static bool scanBinary(const char* filepath, int blockSize, Pred pred)
	{
		if (blockSize <= 0)
		{
			blockSize = 1024 * 4;
		}

		FILE* pFile = NULL;
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
		pFile = _fsopen(filepath, "rb", _SH_DENYNO);
#else
		pFile = fopen(filepath, "rb");
#endif //

		if (!pFile)
		{
			return false;
		}

		char* buffer = new char[blockSize];

		while (!feof(pFile))
		{
			size_t count = fread(buffer, 1, blockSize, pFile);
			if (count == 0)
			{
				break;
			}

			if (!pred(buffer, count))
			{
				break;
			}
		}

		delete[] buffer;

		fclose(pFile);

		return true;
	}

	static int read(const char* filepath, uint8_t* buffer, int maxsize)
	{
		if (!buffer || maxsize <= 0)
		{
			return 0;
		}

		FILE* pFile = NULL;
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
		pFile = _fsopen(filepath, "rb", _SH_DENYNO);
#else
		pFile = fopen(filepath, "rb");
#endif //

		if (!pFile)
		{
			return 0;
		}

		int totalCount = 0;

		uint8_t* out = buffer;
		int size = maxsize;

		while (!feof(pFile) && size > 0)
		{
			int toRead = size < BUFFER_SIZE ? size : BUFFER_SIZE;
			size_t count = fread(out, 1, toRead, pFile);
			if (count == 0)
			{
				break;
			}

			totalCount += (int)count;

			out += (int)count;
			size -= (int)count;

			if ((int)count < toRead)
			{
				break;
			}
		}

		fclose(pFile);

		return totalCount;
	}

};



}


#endif /* TFILEUTIL_H_ */
